import json
import os
import subprocess
import threading
import time
import tkinter as tk
import uuid
from datetime import datetime, timedelta
from tkinter import filedialog, messagebox, ttk

import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="Task", category="tool"))
class TaskView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 任务数据
        self.tasks = []  # 存储所有任务
        self.task_file = "config/tasks.json"  # 任务保存文件
        self.load_tasks()  # 加载保存的任务

        # 定时器线程
        self.check_thread = None
        self.running = True
        self.start_checking()  # 开始检查任务

        # 创建UI
        self.create_ui()

    def create_ui(self):
        """创建用户界面"""
        # 主框架
        self.main_frame = ttk.Frame(self, padding=10)
        self.main_frame.pack(fill=BOTH, expand=True)

        # 顶部控制栏
        self.create_control_bar()

        # 创建分隔符
        ttk.Separator(self.main_frame, orient=HORIZONTAL).pack(fill=X, pady=5)

        # 中间内容区（任务列表+任务配置）
        content_frame = ttk.Frame(self.main_frame)
        content_frame.pack(fill=BOTH, expand=True, pady=5)

        # 任务列表区
        self.create_task_list(content_frame)

        # 任务配置区
        self.create_task_config(content_frame)

        # 创建分隔符
        ttk.Separator(self.main_frame, orient=HORIZONTAL).pack(fill=X, pady=5)

        # 任务执行日志区
        self.create_log_area()

    def create_control_bar(self):
        """创建顶部控制栏"""
        control_bar = ttk.Frame(self.main_frame)
        control_bar.pack(fill=X, pady=5)

        # 新建任务按钮
        ttk.Button(
            control_bar,
            text="新建任务",
            command=self.new_task,
            bootstyle=SUCCESS
        ).pack(side=LEFT, padx=5)

        # 删除选中任务按钮
        ttk.Button(
            control_bar,
            text="删除选中任务",
            command=self.delete_selected_tasks,
            bootstyle=DANGER
        ).pack(side=LEFT, padx=5)

        # 启动选中任务按钮
        ttk.Button(
            control_bar,
            text="启动选中任务",
            command=self.start_selected_tasks,
            bootstyle=PRIMARY
        ).pack(side=LEFT, padx=5)

        # 停止选中任务按钮
        ttk.Button(
            control_bar,
            text="停止选中任务",
            command=self.stop_selected_tasks,
            bootstyle=WARNING
        ).pack(side=LEFT, padx=5)

        # 立即执行选中任务按钮
        ttk.Button(
            control_bar,
            text="立即执行选中任务",
            command=self.execute_selected_tasks,
            bootstyle=INFO
        ).pack(side=LEFT, padx=5)

        # 保存任务按钮
        ttk.Button(
            control_bar,
            text="保存所有任务",
            command=self.save_tasks,
            bootstyle=SECONDARY
        ).pack(side=RIGHT, padx=5)

    def create_task_list(self, parent):
        """创建任务列表区域"""
        task_list_frame = ttk.LabelFrame(parent, text="任务列表", padding=10)
        task_list_frame.pack(side=LEFT, fill=BOTH, expand=True, padx=5)

        # 创建任务列表树视图
        columns = ("name", "script", "time", "interval", "status")
        self.task_tree = ttk.Treeview(
            task_list_frame,
            columns=columns,
            show="headings",
            selectmode=EXTENDED
        )

        # 设置列标题和宽度
        self.task_tree.heading("name", text="任务名称")
        self.task_tree.heading("script", text="关联脚本")
        self.task_tree.heading("time", text="触发时间")
        self.task_tree.heading("interval", text="间隔时间(分钟)")
        self.task_tree.heading("status", text="状态")

        self.task_tree.column("name", width=150)
        self.task_tree.column("script", width=200)
        self.task_tree.column("time", width=120)
        self.task_tree.column("interval", width=100)
        self.task_tree.column("status", width=80)

        # 添加滚动条
        scrollbar = ttk.Scrollbar(
            task_list_frame,
            orient=VERTICAL,
            command=self.task_tree.yview
        )
        scrollbar.pack(side=RIGHT, fill=Y)
        self.task_tree.configure(yscrollcommand=scrollbar.set)

        self.task_tree.pack(fill=BOTH, expand=True)

        # 绑定选择事件
        self.task_tree.bind("<<TreeviewSelect>>", self.on_task_select)

    def create_task_config(self, parent):
        """创建任务配置区域"""
        config_frame = ttk.LabelFrame(parent, text="任务配置", padding=10)
        config_frame.pack(side=RIGHT, fill=BOTH, expand=True, padx=5)

        # 任务ID（隐藏）
        self.task_id_var = tk.StringVar()
        ttk.Label(config_frame, text="ID:").grid(row=0, column=0, sticky=W, pady=5)
        ttk.Entry(config_frame, textvariable=self.task_id_var, state=DISABLED).grid(row=0, column=1, sticky=EW, pady=5)

        # 任务名称
        ttk.Label(config_frame, text="任务名称:").grid(row=1, column=0, sticky=W, pady=5)
        self.task_name_var = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.task_name_var).grid(row=1, column=1, sticky=EW, pady=5)

        # 关联脚本
        ttk.Label(config_frame, text="关联Python脚本:").grid(row=2, column=0, sticky=W, pady=5)
        script_frame = ttk.Frame(config_frame)
        script_frame.grid(row=2, column=1, sticky=EW, pady=5)
        self.script_path_var = tk.StringVar()
        ttk.Entry(script_frame, textvariable=self.script_path_var).pack(side=LEFT, fill=X, expand=True)
        ttk.Button(
            script_frame,
            text="浏览...",
            command=self.browse_script
        ).pack(side=RIGHT, padx=5)

        # 触发时间
        ttk.Label(config_frame, text="首次触发时间:").grid(row=3, column=0, sticky=W, pady=5)
        time_frame = ttk.Frame(config_frame)
        time_frame.grid(row=3, column=1, sticky=EW, pady=5)
        self.trigger_time_var = tk.StringVar()
        ttk.Entry(time_frame, textvariable=self.trigger_time_var).pack(side=LEFT, fill=X, expand=True)
        ttk.Button(
            time_frame,
            text="当前时间",
            command=lambda: self.trigger_time_var.set(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        ).pack(side=RIGHT, padx=5)

        # 间隔时间
        ttk.Label(config_frame, text="执行间隔(分钟):").grid(row=4, column=0, sticky=W, pady=5)
        self.interval_var = tk.StringVar(value="60")
        ttk.Entry(config_frame, textvariable=self.interval_var).grid(row=4, column=1, sticky=EW, pady=5)

        # 备注
        ttk.Label(config_frame, text="备注:").grid(row=5, column=0, sticky=N + W, pady=5)
        self.notes_var = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.notes_var).grid(row=5, column=1, sticky=EW, pady=5)

        # 保存任务配置按钮
        ttk.Button(
            config_frame,
            text="保存任务配置",
            command=self.save_task_config,
            bootstyle=SUCCESS
        ).grid(row=6, column=0, columnspan=2, pady=10)

        # 设置列权重，使输入框可以拉伸
        config_frame.columnconfigure(1, weight=1)

    def create_log_area(self):
        """创建日志区域"""
        log_frame = ttk.LabelFrame(self.main_frame, text="执行日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True, pady=5)

        # 日志文本框
        self.log_text = tk.Text(
            log_frame,
            wrap=tk.WORD,
            state=DISABLED,
            height=10
        )
        self.log_text.pack(fill=BOTH, expand=True)

        # 添加滚动条
        scrollbar = ttk.Scrollbar(
            log_frame,
            orient=VERTICAL,
            command=self.log_text.yview
        )
        scrollbar.pack(side=RIGHT, fill=Y)
        self.log_text.configure(yscrollcommand=scrollbar.set)

    def browse_script(self):
        """浏览选择Python脚本"""
        script_path = filedialog.askopenfilename(
            title="选择Python脚本",
            filetypes=[("Python files", "*.py"), ("All files", "*.*")]
        )
        if script_path:
            self.script_path_var.set(script_path)

    def new_task(self):
        """创建新任务"""
        # 清空配置表单
        self.task_id_var.set(str(uuid.uuid4()))
        self.task_name_var.set("")
        self.script_path_var.set("")
        self.trigger_time_var.set(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        self.interval_var.set("60")
        self.notes_var.set("")

        # 取消选择
        self.task_tree.selection_remove(self.task_tree.selection())

    def save_task_config(self):
        """保存任务配置"""
        # 获取表单数据
        task_id = self.task_id_var.get() or str(uuid.uuid4())
        name = self.task_name_var.get().strip()
        script = self.script_path_var.get().strip()
        trigger_time = self.trigger_time_var.get().strip()
        interval = self.interval_var.get().strip()
        notes = self.notes_var.get().strip()

        # 验证数据
        if not name:
            messagebox.showerror("错误", "任务名称不能为空")
            return

        if not script or not os.path.exists(script):
            messagebox.showerror("错误", "请选择有效的Python脚本")
            return

        try:
            # 验证时间格式
            datetime.strptime(trigger_time, "%Y-%m-%d %H:%M:%S")

            # 验证间隔时间
            if not interval or not interval.isdigit() or int(interval) <= 0:
                raise ValueError("间隔时间必须是正整数")
        except ValueError as e:
            messagebox.showerror("错误", f"时间格式错误: {str(e)}")
            return

        # 创建或更新任务
        task = {
            "id": task_id,
            "name": name,
            "script": script,
            "trigger_time": trigger_time,
            "interval": int(interval),
            "notes": notes,
            "status": "停止",
            "last_run": None,
            "next_run": trigger_time
        }

        # 检查是否是更新现有任务
        existing_index = next((i for i, t in enumerate(self.tasks) if t["id"] == task_id), None)
        if existing_index is not None:
            # 保留状态信息
            task["status"] = self.tasks[existing_index]["status"]
            task["last_run"] = self.tasks[existing_index]["last_run"]
            self.tasks[existing_index] = task
        else:
            self.tasks.append(task)

        # 更新任务列表
        self.update_task_list()

        # 保存任务
        self.save_tasks()

        messagebox.showinfo("成功", "任务配置已保存")

    def on_task_select(self, event):
        """任务选择事件"""
        selection = self.task_tree.selection()
        if selection:
            # 获取选中的第一个任务
            task_id = self.task_tree.item(selection[0])["values"][0]
            task = next((t for t in self.tasks if t["id"] == task_id), None)

            if task:
                # 填充表单
                self.task_id_var.set(task["id"])
                self.task_name_var.set(task["name"])
                self.script_path_var.set(task["script"])
                self.trigger_time_var.set(task["trigger_time"])
                self.interval_var.set(str(task["interval"]))
                self.notes_var.set(task.get("notes", ""))

    def update_task_list(self):
        """更新任务列表"""
        # 清空现有列表
        for item in self.task_tree.get_children():
            self.task_tree.delete(item)

        # 添加所有任务
        for task in self.tasks:
            self.task_tree.insert(
                "",
                END,
                values=(
                    task["id"],
                    task["name"],
                    os.path.basename(task["script"]),
                    task["trigger_time"],
                    task["interval"],
                    task["status"]
                )
            )

    def delete_selected_tasks(self):
        """删除选中的任务"""
        selection = self.task_tree.selection()
        if not selection:
            messagebox.showinfo("提示", "请先选择要删除的任务")
            return

        if messagebox.askyesno("确认", f"确定要删除选中的{len(selection)}个任务吗?"):
            # 获取选中任务的ID
            task_ids = [self.task_tree.item(item)["values"][0] for item in selection]

            # 从任务列表中删除
            self.tasks = [t for t in self.tasks if t["id"] not in task_ids]

            # 更新任务列表
            self.update_task_list()

            # 保存任务
            self.save_tasks()

            messagebox.showinfo("成功", f"已删除{len(selection)}个任务")

    def start_selected_tasks(self):
        """启动选中的任务"""
        selection = self.task_tree.selection()
        if not selection:
            messagebox.showinfo("提示", "请先选择要启动的任务")
            return

        # 获取选中任务的ID
        task_ids = [self.task_tree.item(item)["values"][0] for item in selection]

        # 更新任务状态
        count = 0
        for task in self.tasks:
            if task["id"] in task_ids and task["status"] != "运行中":
                task["status"] = "运行中"
                count += 1

        if count > 0:
            # 更新任务列表
            self.update_task_list()

            # 保存任务
            self.save_tasks()

            messagebox.showinfo("成功", f"已启动{count}个任务")
            self.log(f"已启动{count}个任务")

    def stop_selected_tasks(self):
        """停止选中的任务"""
        selection = self.task_tree.selection()
        if not selection:
            messagebox.showinfo("提示", "请先选择要停止的任务")
            return

        # 获取选中任务的ID
        task_ids = [self.task_tree.item(item)["values"][0] for item in selection]

        # 更新任务状态
        count = 0
        for task in self.tasks:
            if task["id"] in task_ids and task["status"] != "停止":
                task["status"] = "停止"
                count += 1

        if count > 0:
            # 更新任务列表
            self.update_task_list()

            # 保存任务
            self.save_tasks()

            messagebox.showinfo("成功", f"已停止{count}个任务")
            self.log(f"已停止{count}个任务")

    def execute_selected_tasks(self):
        """立即执行选中的任务"""
        selection = self.task_tree.selection()
        if not selection:
            messagebox.showinfo("提示", "请先选择要执行的任务")
            return

        # 获取选中任务的ID
        task_ids = [self.task_tree.item(item)["values"][0] for item in selection]

        # 执行任务
        count = 0
        for task in self.tasks:
            if task["id"] in task_ids:
                threading.Thread(target=self.run_task, args=(task,), daemon=True).start()
                count += 1

        messagebox.showinfo("提示", f"已开始执行{count}个任务")
        self.log(f"已开始执行{count}个任务")

    def run_task(self, task):
        time.sleep(1)  # 解决启动后自动加载脚本log输出在UI初始化之前问题
        """运行任务（执行关联的Python脚本）"""
        try:
            self.log(f"开始执行任务: {task['name']}")

            # 执行Python脚本
            result = subprocess.run(
                ["python", task["script"]],
                capture_output=True,
                text=True,
                check=True
            )

            # 更新任务最后运行时间
            task["last_run"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.save_tasks()

            self.log(f"任务执行成功: {task['name']}")
            if result.stdout:
                self.log(f"任务输出: {result.stdout[:200]}...")  # 只显示前200个字符

        except Exception as e:
            self.log(f"任务执行失败: {task['name']} - 错误: {str(e)}")
            if hasattr(e, 'stdout') and e.stdout:
                self.log(f"标准输出: {e.stdout[:200]}...")
            if hasattr(e, 'stderr') and e.stderr:
                self.log(f"错误输出: {e.stderr[:200]}...")

    def log(self, message):
        """添加日志信息"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {message}\n"

        self.log_text.config(state=NORMAL)
        self.log_text.insert(END, log_entry)
        self.log_text.see(END)  # 滚动到最后
        self.log_text.config(state=DISABLED)

    def start_checking(self):
        """开始检查任务是否需要执行"""
        self.check_thread = threading.Thread(target=self.check_tasks, daemon=True)
        self.check_thread.start()

    def check_tasks(self):
        """检查任务是否到达执行时间"""
        while self.running:
            now = datetime.now()

            for task in self.tasks:
                if task["status"] == "运行中":
                    try:
                        # 解析下次运行时间
                        next_run_time = datetime.strptime(task["next_run"], "%Y-%m-%d %H:%M:%S")

                        # 检查是否到达执行时间
                        if now >= next_run_time:
                            # 执行任务
                            threading.Thread(target=self.run_task, args=(task,), daemon=True).start()

                            # 计算下次运行时间
                            interval = timedelta(minutes=task["interval"])
                            new_next_run = next_run_time + interval

                            # 如果计算的下次运行时间仍在当前时间之前，使用当前时间加上间隔
                            if new_next_run <= now:
                                new_next_run = now + interval

                            task["next_run"] = new_next_run.strftime("%Y-%m-%d %H:%M:%S")
                            self.save_tasks()
                    except Exception as e:
                        self.log(f"检查任务时出错: {task['name']} - {str(e)}")

            # 每分钟检查一次
            time.sleep(60)

    def save_tasks(self):
        """保存任务到文件"""
        try:
            with open(self.task_file, "w", encoding="utf-8") as f:
                json.dump(self.tasks, f, ensure_ascii=False, indent=2)
        except Exception as e:
            self.log(f"保存任务失败: {str(e)}")

    def load_tasks(self):
        """从文件加载任务"""
        try:
            if os.path.exists(self.task_file):
                with open(self.task_file, "r", encoding="utf-8") as f:
                    self.tasks = json.load(f)
        except Exception as e:
            self.log(f"加载任务失败: {str(e)}")
            self.tasks = []

    def on_close(self):
        """关闭窗口时的处理"""
        self.running = False
        if self.check_thread:
            self.check_thread.join(timeout=1.0)
        self.save_tasks()
        self.destroy()

    def create_widgets(self):
        pass
